﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using IWMAG.Scripting.AST.ObjectModel;
using IWMAG.Scripting.Helpers;

namespace IWMAG.Scripting.Interpreter {
    // this is going to be the runtime representation of our values
    public class RunValue {
        protected object _Value;
        protected RuntimeTable Symbol = null;
        protected ScriptEngine Engine = null;

        public static RunValue NoValue {
            get {
                return new RunValue(null);
            }
        }

        public RunValue this[RunValue v] {
            get {
                return ArrayValue[(int)v.IntValue];
            }
            set {
                ArrayValue[(int)v.IntValue] = value;
            }
        }

        public RunValue(object val) {
            Value = val;
        }

        public virtual object Value {
            get {
                if (_Value is CodeExpression) {
                    return GetLateValue().Value;
                }
                return _Value;
            }
            set {
                if (value is RunValue) {
                    RunValue val = value as RunValue;
                    _Value = val.Value;
                    Symbol = val.Symbol;
                    Engine = val.Engine;
                } else {
                    _Value = value;
                }
            }
        }

        public virtual int IntValue {
            get {
                if (_Value is CodeExpression) {
                    return GetLateValue().IntValue;
                }
                return (int) _Value;
            }
        }

        public virtual bool BoolValue {
            get {
                if (_Value is CodeExpression) {
                    return GetLateValue().BoolValue;
                }
                return (bool) _Value;
            }
        }

        public virtual float RealValue {
            get {
                if (_Value is CodeExpression) {
                    return GetLateValue().RealValue;
                }
                return (float) _Value;
            }
        }

        public virtual string StringValue {
            get {
                if (_Value is CodeExpression) {
                    return GetLateValue().StringValue;
                }
                return _Value as string;
            }
        }

        public virtual ArrayRunValue ArrayValue {
            get {
                if (_Value is CodeExpression) {
                    return GetLateValue().ArrayValue;
                } else if (_Value is string) {
                    return new ArrayRunValue(_Value as string);
                }
                return _Value as ArrayRunValue;
            }
        }

        public virtual CodeExpression LateBinding {
            get {
                return _Value as CodeExpression;
            }
        }

        protected RunValue GetLateValue() {
            Reference<RunValue> val = RunValue.NoValue;
            foreach (Continuation wait in LateBinding.ValueOf(Engine, Symbol, val)) {
                if (wait.Command == Continuation.Token.Killed) {
                    throw new LatebindFailedException();
                }
            }
            return val.ReferencedValue;
        }

        public void MakeLate(ScriptEngine engine, RuntimeTable sym, CodeExpression obj) {
            Engine = engine;
            Symbol = sym;
            Value = obj;

            foreach (Continuation wait in obj.ValueOf(engine, sym, RunValue.NoValue)) ;
        }

        public override string ToString() {
            if (Value is CodeExpression) {
                return GetLateValue().ToString();
            }
            return Value.ToString();
        }
    }
}
